﻿using System;
using System.Diagnostics;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using uTILLIty.Rave.Contract.Exception;
using uTILLIty.Rave.Contract.Job;
using uTILLIty.Rave.Contract.Schema;

namespace uTILLIty.Rave.Core.Manager
{
  /// <summary>
  /// Handles <see cref="Job"/>s
  /// </summary>
	public class JobManager
	{
    /// <summary>
    /// Loads a <see cref="Job"/> from the specified stream
    /// </summary>
    /// <param name="data">the stream representing a job</param>
    /// <param name="jobSource">used to set <see cref="Job.JobSource"/>, to be able to initialize logging</param>
		public virtual Job LoadJob(Stream data, string jobSource)
		{
			if (data == null)
				throw new ArgumentNullException("data");

			if (data.Position != 0 && data.CanSeek)
				data.Seek(0, SeekOrigin.Begin);

			var settings = new XmlReaderSettings { ValidationType = ValidationType.None };
			settings.ValidationEventHandler += OnValidationEvent;
			settings.ValidationType = ValidationType.Schema;
			settings.Schemas.Add(Schema.WellKnownSchemas.GetSchemaResource<WellKnownSchemas>("Job.xsd"));

			var serializer = new XmlSerializer(typeof(Job));
			using (var reader = XmlReader.Create(data, settings))
			{
				var job = (Job)serializer.Deserialize(reader);
				job.JobSource = new FileInfo(jobSource).FullName;
				InitializeLogging(job);
				return job;
			}
		}

		/// <summary>
		/// Initializes the logging-engine required by all modules used to process the template based on
		/// <see cref="Job.JobSource"/> and <see cref="Job.LogLevel"/>
		/// </summary>
    public virtual void InitializeLogging(Job job)
		{
			if (job.TraceSource == null)
			{
				var logFile = Path.ChangeExtension(job.JobSource, ".log");
				logFile = job.AddJobIdToFilename(logFile);
				job.TraceSource = new TraceSource("Job", job.LogLevel);
				if (job.LogLevel != SourceLevels.Off)
					job.TraceSource.Listeners.Add(new TextWriterTraceListener(logFile));
			}
			job.TraceSource.Switch.Level = job.LogLevel;
		}

		private void OnValidationEvent(object sender, ValidationEventArgs e)
		{
			//TODO: log
			switch (e.Severity)
			{
				case XmlSeverityType.Error:
					throw new ConfigurationErrorException(string.Format(Properties.Resources.ValidationErrorInJobXml, e.Message), e.Exception);
				case XmlSeverityType.Warning:
					break;
			}
		}
	}
}